package com.ruoyi.web.controller.api;


import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cat.domain.*;
import com.ruoyi.cat.domain.VO.DrawResult;
import com.ruoyi.cat.domain.VO.PrizeDrawVO;
import com.ruoyi.cat.service.*;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.OrderUtil;
import com.ruoyi.common.utils.ProbabilityUtils;

import com.ruoyi.common.utils.bean.BeanUtils;
import groovy.util.logging.Log4j;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Api(tags = "api-抽奖相关接口")
@RestController
@RequestMapping("/api/prizeDraw")
public class PrizeDrawController extends BaseController {


    @Autowired
    private ICatChanceService catChanceService;

    @Autowired
    private ICatChancesService iCatChancesService;

    @Autowired
    private ICatPrizeDrawService iCatPrizeDrawService;

    @Autowired
    private ICatActivityTableService iCatActivityTableService;


    @Autowired
    private ICatWinningRecordsService iCatWinningRecordsService;


    @Autowired
    private DrawLotteryService catRaffleService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String PREFIX = "draw:";



    @ApiOperation("api-获取中奖记录")
    @GetMapping("getPrizeDraw")
    public AjaxResult getPrizeDraw(PrizeDrawVO prizeDrawVO){
        CatWinningRecords catWinningRecords = iCatWinningRecordsService.getWinningData(prizeDrawVO.getId(),prizeDrawVO.getUserId());
        if (catWinningRecords == null){
            return error("没有中奖记录");
        }
        return success(catWinningRecords);
    }

    @ApiOperation("api-抽奖接口")
    @PostMapping("raffle")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult raffle(@RequestBody @Valid PrizeDrawVO prizeDrawVO) {
        log.info("抽奖接口 ----- Received request: {}", prizeDrawVO);
        // 参数校验
        if (prizeDrawVO == null || prizeDrawVO.getId() == null || prizeDrawVO.getUserId() == null) {
            return error("参数不能为空");
        }

        // 查询活动信息并校验
        CatActivityTable catActivityTable = iCatActivityTableService.selectCatActivityTableById(prizeDrawVO.getId());
        if (catActivityTable == null) {
            return error("活动不存在");
        }

        // 检查奖品库存
        if (catActivityTable.getGiftTotal() <= 0) {
            return error("奖品已经抽完");
        }

        // 首先检查用户是否已经中过奖
        CatWinningRecords existingWinRecord = iCatWinningRecordsService.getWinningData(prizeDrawVO.getId(), prizeDrawVO.getUserId());
        if (existingWinRecord != null) {
            return success(existingWinRecord);
        }

        // 进行抽奖
        CatChances catChance = new CatChances();
        catChance.setActivityId(prizeDrawVO.getId());
        List<CatChances> list = iCatChancesService.selectCatChancesList(catChance);
        if (list.isEmpty()) {
            return error("抽奖配置异常");
        }

        // 查询用户已有的抽奖记录
        CatPrizeDraw draw = new CatPrizeDraw();
        draw.setArticleId(prizeDrawVO.getId());
        draw.setUserId(prizeDrawVO.getUserId());
        List<CatPrizeDraw> prizeDraws = iCatPrizeDrawService.selectCatPrizeData(draw);

        CatPrizeDraw drawData = new CatPrizeDraw();
        drawData.setArticleId(prizeDrawVO.getId());
        drawData.setUserId(prizeDrawVO.getUserId());
        List<CatPrizeDraw> prizeDrawsData = iCatPrizeDrawService.selectCatPrize(drawData);

        // 执行抽奖逻辑
       // CatChances zj = drawLottery(list, prizeDraws);
        CatChances zj = catRaffleService.drawCard(prizeDrawVO.getId(), prizeDrawVO.getUserId(),prizeDrawsData);


        // 检查抽奖机会
        CatChance catCha = new CatChance();
        catCha.setUserId(prizeDrawVO.getUserId());
        catCha.setArticleId(prizeDrawVO.getId());
        catCha.setReferenceId(prizeDrawVO.getReferenceId());
        List<CatChance> catChances = catChanceService.selectCatChanceList(catCha);
        if (catChances.isEmpty()) {
            catCha.setRemainingChances(catActivityTable.getFirstChance() - 1);
            catChanceService.insertCatChance(catCha);
        } else {
            CatChance currentChance = catChances.get(0);
            if (currentChance.getRemainingChances() <= 0) {
                return error("抽奖机会已经用完");
            }
            catCha.setRemainingChances(currentChance.getRemainingChances() - 1);
            catCha.setId(currentChance.getId());
            catChanceService.updateCatChance(catCha);
        }

        // 记录本次抽奖结果
        CatPrizeDraw catPrizeDraw = new CatPrizeDraw();
        catPrizeDraw.setArticleId(prizeDrawVO.getId());
        catPrizeDraw.setUserId(prizeDrawVO.getUserId());
        catPrizeDraw.setChancesId(zj.getId());
        iCatPrizeDrawService.insertCatPrizeDraw(catPrizeDraw);

        // 将本次抽奖结果添加到已有记录中，再检查是否集齐
        prizeDraws.add(catPrizeDraw); // 添加本次抽奖结果到列表中

        // 检查是否集齐所有奖品
        Set<Long> obtainedChancesIds = prizeDraws.stream()
                .map(CatPrizeDraw::getChancesId)
                .collect(Collectors.toSet());
        Set<Long> allChancesIds = list.stream()
                .map(CatChances::getId)
                .collect(Collectors.toSet());

        // 如果集齐了所有奖品，立即创建中奖记录
        if (obtainedChancesIds.size() == allChancesIds.size() && obtainedChancesIds.containsAll(allChancesIds)) {
            // 再次检查是否已存在中奖记录，避免并发问题
            CatWinningRecords winningRecord = iCatWinningRecordsService.getWinningData(prizeDrawVO.getId(), prizeDrawVO.getUserId());
            if (winningRecord == null) {
                // 生成中奖记录
                CatWinningRecords catWinningRecords = new CatWinningRecords();
                catWinningRecords.setUserId(prizeDrawVO.getUserId());
                catWinningRecords.setActivityId(prizeDrawVO.getId());
                catWinningRecords.setRedemptionCode(OrderUtil.generateVerificationCode(8));
                catWinningRecords.setEndTime(catActivityTable.getEndTime());
                iCatWinningRecordsService.insertCatWinningRecords(catWinningRecords);

                catActivityTable.setGiftTotal(catActivityTable.getGiftTotal() - 1);
                iCatActivityTableService.updateCatActivity(catActivityTable);

                return success(zj);
            } else {
                return success(zj);
            }
        }

        // 如果没有集齐所有奖品，返回本次抽中的奖品
        return success(zj);
    }

   /* @ApiOperation("api-抽奖接口-Redis优化版")
    @PostMapping("raffle")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult raffle(@RequestBody @Valid PrizeDrawVO prizeDrawVO) {
        log.info("抽奖接口 ----- Received request: {}", prizeDrawVO);

        // 使用Redis分布式锁防止用户并发抽奖
        String lockKey = "raffle:lock:" + prizeDrawVO.getUserId() + ":" + prizeDrawVO.getId();
        String lockValue = UUID.randomUUID().toString();
        boolean locked = false;

        try {
            // 尝试获取分布式锁，过期时间5秒
            locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 2, TimeUnit.SECONDS);
            if (!locked) {
                return error("操作过于频繁，请稍后再试");
            }

            // 参数校验
            if (prizeDrawVO == null || prizeDrawVO.getId() == null || prizeDrawVO.getUserId() == null) {
                return error("参数不能为空");
            }

            // 查询活动信息并校验
            // 先从Redis缓存获取活动信息
            String activityCacheKey = "raffle:activity:" + prizeDrawVO.getId();
            CatActivityTable catActivityTable = null;
            String activityJson = redisTemplate.opsForValue().get(activityCacheKey);

            if (activityJson != null) {
                catActivityTable = JSONObject.parseObject(activityJson, CatActivityTable.class);
            } else {
                catActivityTable = iCatActivityTableService.selectCatActivityTableByIdTask(prizeDrawVO.getId());
                if (catActivityTable != null) {
                    // 缓存活动信息，有效期24小时
                    redisTemplate.opsForValue().set(activityCacheKey, JSONObject.toJSONString(catActivityTable), 24, TimeUnit.HOURS);
                }
            }

            if (catActivityTable == null) {
                return error("活动不存在");
            }

            // 检查奖品库存 - 使用Redis原子递减操作
            String giftCountKey = "raffle:gift_count:" + prizeDrawVO.getId();
            // 初始化或获取库存
            Long giftCount = redisTemplate.opsForValue().get(giftCountKey) != null ?
                    Long.valueOf(redisTemplate.opsForValue().get(giftCountKey)) : catActivityTable.getGiftTotal();

            if (giftCount == null || giftCount == 0) {
                return error("奖品已经抽完");
            }

            // 检查用户是否已经中过奖 - 使用Redis缓存
            String winRecordKey = "raffle:win_record:" + prizeDrawVO.getId() + ":" + prizeDrawVO.getUserId();
            String winRecordJson = redisTemplate.opsForValue().get(winRecordKey);
            CatWinningRecords existingWinRecord = null;

            if (winRecordJson != null) {
                existingWinRecord = JSONObject.parseObject(winRecordJson, CatWinningRecords.class);
            } else {
                existingWinRecord = iCatWinningRecordsService.getWinningData(prizeDrawVO.getId(), prizeDrawVO.getUserId());
                if (existingWinRecord != null) {
                    // 缓存中奖记录，永久有效
                    redisTemplate.opsForValue().set(winRecordKey, JSONObject.toJSONString(existingWinRecord));
                }
            }

            if (existingWinRecord != null) {
                return success(existingWinRecord);
            }

            // 查询用户抽奖机会
            CatChance catCha = new CatChance();
            catCha.setUserId(prizeDrawVO.getUserId());
            catCha.setArticleId(prizeDrawVO.getId());
            catCha.setReferenceId(prizeDrawVO.getReferenceId());

            // 使用Redis缓存用户抽奖机会
            String chanceKey = "raffle:chance:" + prizeDrawVO.getId() + ":" + prizeDrawVO.getUserId();
            Long remainingChances = null;

            String chanceJson = redisTemplate.opsForValue().get(chanceKey);
            if (chanceJson != null) {
                remainingChances = Long.valueOf(chanceJson);
            } else {
                List<CatChance> catChances = catChanceService.selectCatChanceList(catCha);
                if (catChances.isEmpty()) {
                    remainingChances = catActivityTable.getFirstChance();
                    catCha.setRemainingChances(remainingChances);
                    catChanceService.insertCatChance(catCha);
                } else {
                    CatChance currentChance = catChances.get(0);
                    remainingChances = currentChance.getRemainingChances();
                    catCha.setId(currentChance.getId());
                }
                // 缓存用户抽奖机会，有效期24小时
                redisTemplate.opsForValue().set(chanceKey, remainingChances.toString(), 24, TimeUnit.HOURS);
            }

            if (remainingChances <= 0) {
                return error("抽奖机会已经用完");
            }

            // 使用Redis递减抽奖机会
            Long newChances = redisTemplate.opsForValue().decrement(chanceKey);
            if (newChances < 0) {
                // 恢复抽奖机会
                redisTemplate.opsForValue().increment(chanceKey);
                return error("抽奖机会不足");
            }

            // 查询用户已有的抽奖记录
            CatPrizeDraw draw = new CatPrizeDraw();
            draw.setArticleId(prizeDrawVO.getId());
            draw.setUserId(prizeDrawVO.getUserId());
            List<CatPrizeDraw> prizeDraws = iCatPrizeDrawService.selectCatPrizeData(draw);

            CatPrizeDraw drawData = new CatPrizeDraw();
            drawData.setArticleId(prizeDrawVO.getId());
            drawData.setUserId(prizeDrawVO.getUserId());
            List<CatPrizeDraw> prizeDrawsData = iCatPrizeDrawService.selectCatPrize(drawData);

            // 执行抽奖逻辑
            CatChances zj = catRaffleService.drawCard(prizeDrawVO.getId(), prizeDrawVO.getUserId(), prizeDrawsData);

            // 记录本次抽奖结果
            CatPrizeDraw catPrizeDraw = new CatPrizeDraw();
            catPrizeDraw.setArticleId(prizeDrawVO.getId());
            catPrizeDraw.setUserId(prizeDrawVO.getUserId());
            catPrizeDraw.setChancesId(zj.getId());
            iCatPrizeDrawService.insertCatPrizeDraw(catPrizeDraw);

            // 使用Redis缓存新的抽奖记录
            String userDrawsKey = "raffle:user_draws:" + prizeDrawVO.getId() + ":" + prizeDrawVO.getUserId();
            // 将新抽奖记录加入缓存
            redisTemplate.opsForList().rightPush(userDrawsKey, JSONObject.toJSONString(catPrizeDraw));
            // 设置缓存有效期
            redisTemplate.expire(userDrawsKey, 7, TimeUnit.DAYS);

            // 将本次抽奖结果添加到已有记录中，再检查是否集齐
            prizeDraws.add(catPrizeDraw);

            // 使用Redis存储所有抽奖信息的ID集合，用于快速判断是否集齐
            CatChances catChance = new CatChances();
            catChance.setActivityId(prizeDrawVO.getId());
            List<CatChances> list = iCatChancesService.selectCatChancesList(catChance);

            // 检查是否集齐所有奖品
            Set<Long> obtainedChancesIds = prizeDraws.stream()
                    .map(CatPrizeDraw::getChancesId)
                    .collect(Collectors.toSet());
            Set<Long> allChancesIds = list.stream()
                    .map(CatChances::getId)
                    .collect(Collectors.toSet());

            // 如果集齐了所有奖品，立即创建中奖记录
            if (obtainedChancesIds.size() == allChancesIds.size() && obtainedChancesIds.containsAll(allChancesIds)) {
                // 使用Redis分布式锁保证只创建一次中奖记录
                String winLockKey = "raffle:win_lock:" + prizeDrawVO.getId() + ":" + prizeDrawVO.getUserId();
                String winLockValue = UUID.randomUUID().toString();
                boolean winLocked = false;

                try {
                    winLocked = redisTemplate.opsForValue().setIfAbsent(winLockKey, winLockValue, 10, TimeUnit.SECONDS);
                    if (winLocked) {
                        // 再次检查是否已存在中奖记录，避免并发问题
                        CatWinningRecords winningRecord = iCatWinningRecordsService.getWinningData(prizeDrawVO.getId(), prizeDrawVO.getUserId());
                        if (winningRecord == null) {
                            // 生成中奖记录
                            CatWinningRecords catWinningRecords = new CatWinningRecords();
                            catWinningRecords.setUserId(prizeDrawVO.getUserId());
                            catWinningRecords.setActivityId(prizeDrawVO.getId());
                            catWinningRecords.setRedemptionCode(OrderUtil.generateVerificationCode(8));
                            catWinningRecords.setEndTime(catActivityTable.getEndTime());
                            iCatWinningRecordsService.insertCatWinningRecords(catWinningRecords);

                            // 缓存中奖记录
                            redisTemplate.opsForValue().set(winRecordKey, JSONObject.toJSONString(catWinningRecords));

                            // 原子减少库存
                            Long remainingGift = redisTemplate.opsForValue().decrement(giftCountKey);

                            // 同步更新数据库
                            catActivityTable.setGiftTotal(remainingGift.longValue());
                            iCatActivityTableService.updateCatActivity(catActivityTable);
                        }
                    }
                } finally {
                    // 释放锁
                    if (winLocked && redisTemplate.opsForValue().get(winLockKey).equals(winLockValue)) {
                        redisTemplate.delete(winLockKey);
                    }
                }

                return success(zj);
            }

            // 更新数据库中的抽奖机会
            catCha.setRemainingChances(newChances.longValue());
            catChanceService.updateCatChance(catCha);

            // 如果没有集齐所有奖品，返回本次抽中的奖品
            return success(zj);
        } finally {
            // 释放锁
            if (locked && redisTemplate.opsForValue().get(lockKey).equals(lockValue)) {
                redisTemplate.delete(lockKey);
            }
        }
    }*/



}
